﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace DFControlLibrary
{
    public delegate void OnGetSmileEventHandler(object sender, int smile, Image image);

    public partial class VideoPanel : DoubleBufferPanel
    {        
        // カメラ制御クラス
        private static DXCapture _dxcam = null;

        // fps(一秒フレーム数)
        private int _frameCapture = 10;

        // fps(一秒フレーム数)
        private int _frameSmile = 4;

        // 笑顔度情報リスト
        private FaceInfoList _lstFace = null;

        // 笑顔度情報更新フラッグ
        private volatile bool _isUpdateFaceInfo = false;

        public delegate void OnCapturedDelegate(WebcamEventArgs e);
        public delegate void OnTimerCaptureDelegate();
        public delegate void OnTimerSmileDelegate();

        private DXCapture.WebCamEventHandler ImageCapturedEvent = null;

        // 笑顔度取得イベント
        public event OnGetSmileEventHandler GetSmileEvent;

        // 笑顔度取得画像キュー
        private static Queue<Image> _queueSmile = new Queue<Image>();

        // 笑顔度取得用スレッド
        private static System.Threading.Thread _threadGetSmile = null;

        // 終了フラッグ
        private volatile bool _bQuit = false;

        // 映像画像を更新中か？
        private volatile bool _bUpdate = false;

        // ログオブジェクト
        private Object _thisLock = new Object();

        // 待ち時間
        private const int WAIT_TIME = 200;


        [Description("fps(一秒フレーム数)"), Category("Data")]
        public int FrameCapture
        {
            get
            {
                return _frameCapture;
            }
            set
            {
                if (value < 0)
                    _frameCapture = Constants.SHOW_FRAME_NUMBER;
                else
                    _frameCapture = value;
            }
        }

        [Description("fps(一秒フレーム数)"), Category("Data")]
        public int FrameSmile
        {
            get
            {
                return _frameSmile;
            }
            set
            {
                if (value < 0)
                    _frameSmile = Constants.SMILE_FRAME_NUMBER;
                else
                    _frameSmile = value;
            }
        }

        public VideoPanel()
        {
            InitializeComponent();

            if (_dxcam == null)
                _dxcam = new DXCapture(this, 0);

            ImageCapturedEvent = new DXCapture.WebCamEventHandler(webcam_ImageCaptured);
        }

        ~VideoPanel()
        {            
        }

        /// <summary>
        /// パネルのサイズ調整
        /// </summary>
        public void FitToImage()
        {
            try
            {
                double w = (double)this.Width / _dxcam.CaptureWidth;
                double h = (double)this.Height / _dxcam.CaptureHeight;
                if (w > h)
                {
                    int width = (int)(_dxcam.CaptureWidth * h + 0.5);
                    this.Left = (this.Width - width) / 2;
                    this.Width = width;
                }
                else
                {
                    int height = (int)(_dxcam.CaptureHeight * w + 0.5);
                    this.Top = (this.Height - height) / 2;
                    this.Height = height;
                }
            }
            catch { }
        }

        /// <summary>
        /// カメラ映像表示開始
        /// </summary>
        public bool StartCapture()
        {
            if (!_dxcam.IsActive)
            {
                if (!_dxcam.InitVideo())
                    return false;
                Thread.Sleep(300);
            }

            _bQuit = false;
            _dxcam.ImageCaptured += ImageCapturedEvent; 
            timer_capture.Interval = 1000 / _frameCapture;
            timer_smile.Interval = 1000 / _frameSmile;
            timer_capture.Start();
            timer_smile.Start();
            return true;
        }

        /// <summary>
        /// カメラ映像表示終了
        /// </summary>
        public void StopCapture()
        {
            timer_smile.Stop();
            timer_capture.Stop();
            _dxcam.ImageCaptured -= ImageCapturedEvent;
            if (_threadGetSmile != null)
            {
                _bQuit = true;
                Monitor.Enter(_queueSmile);
                Monitor.PulseAll(_queueSmile);
                Monitor.Exit(_queueSmile);
                _threadGetSmile.Join();
                _threadGetSmile = null;
            }
        }

        /// <summary>
        /// カメラ映像表示続き
        /// </summary>
        public void ContinueCapture()
        {
            // change the capture time frame            
        }

        /// <summary>
        /// 画像のキャプチャイベント
        /// </summary>
        /// <param name="source"></param>
        /// <param name="e"></param>
        void webcam_ImageCaptured(object source, WebcamEventArgs e)
        {
            BeginInvoke(new OnCapturedDelegate(OnCaptured), e);
        }

        /// <summary>
        /// 画像キャプチャ―した時の処理
        /// </summary>
        /// <param name="e">画像キャプチャ―情報</param>
        void OnCaptured(WebcamEventArgs e)
        {
            try
            {
                if (_bUpdate)
                    return;
                else
                    _bUpdate = true;

                // 左右反転
                e.WebCamImage.RotateFlip(RotateFlipType.Rotate180FlipY);

                if (_isUpdateFaceInfo)
                {
                    // 笑顔度取得用スレッド開始
                    if (_threadGetSmile == null)
                    {
                        _threadGetSmile = new Thread(new ThreadStart(threadOutputProc));
                        _threadGetSmile.IsBackground = true;
                        _threadGetSmile.Start();
                    }

                    // 笑顔度取得画像更新
                    Image bkImg = new Bitmap(e.WebCamImage);
                    Monitor.Enter(_queueSmile);
                    _queueSmile.Clear();
                    _queueSmile.Enqueue(bkImg);
                    Monitor.PulseAll(_queueSmile);
                    Monitor.Exit(_queueSmile);
                }

                // 枠描画               
                if (Monitor.TryEnter(_thisLock, WAIT_TIME))
                {
                    try
                    {
                        BorderDrawer.DrawScoreAndBorder(e.WebCamImage, _lstFace);
                    }
                    finally
                    {
                        Monitor.Exit(_thisLock);
                    }
                }

                // 背景画像更新 
                Image old = this.BackgroundImage;
                this.BackgroundImage = e.WebCamImage;
                if (old != null)
                    old.Dispose();

                // タイマ開始
                timer_capture.Start();
            }
            catch
            {
            }
            finally
            {
                _bUpdate = false;
            }
        }
        
        /// <summary>
        /// タイマイベント
        /// </summary>        
        private void timer_Tick(object sender, EventArgs e)
        {
            if (sender == timer_capture)
            {
                OnTimerCapture();
            }
            else if (sender == timer_smile)
            {                
                OnTimerSmile();
            }
        }

        /// <summary>
        /// 画像キャプチャ―タイマの処理
        /// </summary>
        private void OnTimerCapture()
        {
            timer_capture.Stop();
            if (_dxcam.IsActive)
                _dxcam.StartGrabber();
        }

        /// <summary>
        /// 笑顔度情報更新処理
        /// </summary>
        /// <param name="lst">新しい笑顔度情報リスト</param>
        private void SetSmileInfo(FaceInfoList lst)
        {
            if (Monitor.TryEnter(_thisLock, WAIT_TIME))
            {
                try
                {
                    if (_lstFace != null)
                        _lstFace.Clear();
                    _lstFace = lst;
                }
                finally
                {
                    Monitor.Exit(_thisLock);
                }
            }
        }

        /// <summary>
        /// 笑顔度情報更新タイマの処理
        /// </summary>
        private void OnTimerSmile()
        {
            try
            {
                _isUpdateFaceInfo = true;
            }
            catch
            {                
            }
        }

        /// <summary>
        /// 笑顔度取得レッド処理
        /// </summary>
        private void threadOutputProc()
        {
            while (true)
            {
                // 終了する
                if (_bQuit && (_queueSmile.Count == 0))
                {
                    break;
                }

                /* 50ミリスリープする */
                Thread.Sleep(50);

                try
                {
                    Monitor.Enter(_queueSmile);
                    if (_queueSmile.Count > 0)
                    {
                        // 出力する
                        FaceInfoList lstFace = null;
                        Image img = _queueSmile.Dequeue();
                        Monitor.Exit(_queueSmile);

                        //uint res = GetFaceInfo(img, out lstFace);
                        //if (res == RTN_CODE_SUCCESS)
                        //{
                        //    SetSmileInfo(lstFace);
                        //}                        

                        if ((GetSmileEvent != null) && (lstFace != null) && (lstFace.Count > 0))
                        {
                            GetSmileEvent(this, lstFace[0].SmileValue, img);
                        }
                    }
                    else
                    {
                        Monitor.Wait(_queueSmile, WAIT_TIME);

                        //queueをアンロックする
                        Monitor.Exit(_queueSmile);
                    }
                }
                catch { }
            }            
        }
    }

    public class DoubleBufferPanel : Panel
    {
        public DoubleBufferPanel()
        {
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
        }
    }
}
